import store from '@/store'
import {guid, getWSBaseUrl} from "@/utils/util";
import {navTo, checkModuleKey} from "@/core/app";
import Tool from "@/utils/tool";
import {imAction, imMessageType, imOfflinePullType, imSenderRole, imMessageStatus} from "@/common/constant/im";
import { getPrivateOfflineMessage } from "@/api/message";
import { audioPlayer } from '@/utils/audioPlayer'
import OrderStatusEnum from "@/common/enum/order/orderStatus"
import PickerStatusEnum from "@/common/enum/setting/pickerStatus"
import { pushOpen } from '@/api/iospush';

const APP_CHANNEL = "ios"
const APP_PACKAGE = "com.jthe.jmessage"
// 特殊的消息类型，代表被服务端强制下线
const ACTION_999 = "999"
// 握手鉴权常量
const KEY_HANDSHAKE = "client_handshake"
const CODE_UNAUTHORIZED = "401"
const KEY_CLIENT_BIND = "client_bind"
// 建立绑定时的前缀常量
const UID_BIND_PREFIX = 'STORE_'
const TAG_BIND_PREFIX = 'ST'
const PUSH_TAG_BIND_PREFIX = 'PS'
// 需要发送的心跳数据
const PONG_BODY = "PONG"
// IM权限KEY
const PERMISSION_KEY = 'ly_tab_message'

const SendMessageType = {
  /**
   * 心跳回复
   */
  PONG: 0,
  /**
   * 发送消息
   */
  SENT_BODY: 3
}
const MessageType = {
  /**
   * 心跳
   */
  PING: 1,
  /**
   * 普通消息
   */
  MESSAGE: 2,
  /**
   * 异常消息
   */
  REPLY_BODY: 4
}

export default class WebSocketIM {
  constructor(options) {
    // 默认配置
    const defaultConfig = {
      url: getWSBaseUrl(),     // WebSocket 服务地址 (必填)
      maxReconnect: 50,        // 最大重连次数
      reconnectInterval: 5000, // 重连间隔（毫秒）
      onMessage: () => {},     // 收到消息回调
      onStatusChange: () => {} // 连接状态变化回调
    }

    this.config = { ...defaultConfig, ...options }
    this.reconnectCount = 0            // 当前重连次数
    this.init()
  }

  /**
   * 初始化
   */
  init() {
    this.ws = null                   // WebSocket 实例
    this.reconnectTimer = null       // 重连定时器
  }

  /**
   * 链接socket
   * @param manualStop 是否手动关闭
   */
  connect(manualStop = true) {
    if (this.ws) this.close(manualStop);

    const token = store.getters.token
    const header = {}
    if (token) {
      header.Authorization = token
    }
    // 创建连接（使用uni-app的SocketTask API）
    this.ws = uni.connectSocket({
      url: this.config.url,
      header,
      // #ifdef MP-WEIXIN
      method: 'POST',
      // #endif
      success: () => {
        setTimeout(() => {
          this._bindEvents()
        })
      },
      fail: (err) => {
        this._handleError(err)
      }
    })
  }

  /**
   * 获取vuex里面需要的信息
   * @private
   */
  _getStoreInfo() {
    const shops = store.getters.userInfo.shops
    return {
      // 登录用户ID
      uid: store.getters.userInfo.id,
      // 用户当前选中的门店id
      shopId: store.getters.userInfo.shopId,
      // 用户拥有权限的门店列表
      shops: shops?.length ? shops : [],
      // 用户当前选中的商户id
      tenantId: store.getters.tenant.id,
      // 当前系统版本号
      appVersion: store.getters.appVersion
    }
  }

  /**
   * 绑定事件监听
   * @private
   */
  _bindEvents() {
    // 确保socket实例存在
    if (!this.ws) {
      console.error('无法绑定事件：WebSocket实例不存在');
      return;
    }
    const { uid, shopId, shops, tenantId, appVersion } = this._getStoreInfo()
    let deviceId = uni.getStorageSync('uuid_deviceId')
    if(!uid) return

    // 使用uni-app的SocketTask API事件监听方式
    this.ws.onOpen(() => {
      console.log('WebSocket 连接成功');
      if (!deviceId) {
        deviceId = guid()
        uni.setStorageSync('uuid_deviceId', deviceId)
      }

      let tag = ''
      // #ifdef APP-PLUS
      if (shopId !== '0') {
        tag = `${PUSH_TAG_BIND_PREFIX}${shopId},`
      }
      // #endif
      // 注册IM消息tag
      if (checkModuleKey(PERMISSION_KEY)) {
        tag += `${TAG_BIND_PREFIX}${shopId}`

        if (shopId === '0') {
          // 总部下没有门店，则关闭连接
          if (shops?.length === 0) {
            this.close()
            return
          }
          // 总部需要批量注册门店
          shops.forEach((shopItem, index) => {
            if (index === 0) {
              tag = `${TAG_BIND_PREFIX}${shopItem.id}`
            } else {
              tag += `,${TAG_BIND_PREFIX}${shopItem.id}`
            }
          })
        }
      }
      const dataBody = {
        uid: `${UID_BIND_PREFIX}${uid}`,
        channel: APP_CHANNEL,
        appVersion,
        packageName: APP_PACKAGE,
        tenantId,
        deviceId
      }
      if (tag) {
        dataBody.tag = tag
      }
      const body = {
        key: KEY_CLIENT_BIND,
        timestamp: new Date().getTime(),
        data: dataBody
      }
      console.log('socket绑定信息', JSON.stringify(dataBody))

      this._sendRawMessage({
        type: SendMessageType.SENT_BODY,
        content: JSON.stringify(body)
      }, () => {
        if (checkModuleKey(PERMISSION_KEY)) {
          setTimeout(() => {
            // 绑定成功后拉取离线消息
            getPrivateOfflineMessage('0', {
              load: false,
              isPrompt: false
            }).then(res => {}).catch(() => {})
          }, 1000)
        }
      })
      this.reconnectCount = 0;
      // 关闭重连定时器
      if (this.reconnectTimer) {
        clearTimeout(this.reconnectTimer)
      }
      //绑定ios apns暂时写在这
      this._apnsOpen(uuid);
    });

    this.ws.onMessage((res) => {
      try {
        const data = JSON.parse(res.data);
        this._handleReceivedMessage(data);
      } catch (e) {
        console.warn('log.ws.onMessage', e, res.data)
      }
    });

    this.ws.onClose(() => {
      console.log('WebSocket 连接关闭');
      this._scheduleReconnect();
    });

    this.ws.onError((err) => {
      this._handleError(err);
    });
  }

  /**
   * 关闭连接
   * @param manualStop 是否手动关闭
   */
  close(manualStop = true) {
    this.manualStop = manualStop
    this.ws?.close();
    clearTimeout(this.reconnectTimer);
    this.init();
  }

  /**
   * 发送消息
   * @param message
   * @param callback
   * @private
   */
  _sendRawMessage(message, callback = undefined) {
    this.ws.send({
      data: JSON.stringify(message),
      success: () => {
        callback && callback()
      },
      fail: () => {}
    });
  }

  /**
   * 处理Alert消息
   * @param {Object} title
   * @param {any} msgContent
   */
  _handleAlertMessage(title, msgContent){
    // #ifdef APP-PLUS
    const pickerStatus = store.getters.pickerStatus
    const userInfo = store.getters.userInfo
    try {
      msgContent = JSON.parse(msgContent)
    } catch (e) {
      msgContent = {}
    }

    switch(title) {
      case 'pick_wait_distribution':
        if (pickerStatus === PickerStatusEnum.NO.value) {
          // 待指派
          audioPlayer.addAudio('/static/mp3/audio_pick_distribution.mp3');
        }
        break
      case 'pick_wait_rob':
        // 待抢单
        audioPlayer.addAudio('/static/mp3/audio_pick_rob.mp3');
        break
      case 'pick_wait_turn':
        if (pickerStatus === PickerStatusEnum.NO.value) {
          // 待转派
          audioPlayer.addAudio('/static/mp3/audio_pick_turn.mp3');
        }
        break
      case 'pick_wait_review':
        if (pickerStatus === PickerStatusEnum.NO.value) {
          // 待复核
          audioPlayer.addAudio('/static/mp3/audio_pick_review.mp3');
        }
        break
      case 'pick_wait_picking':
        if (pickerStatus !== PickerStatusEnum.NO.value && userInfo.nickName === msgContent.pickerName) {
          // 待拣货
          audioPlayer.addAudio('/static/mp3/audio_pick_new.mp3');
        }
        break
      case 'pick_adjust':
        // 拣货单调整
        break
      case 'order_new':
        // 新订单
        audioPlayer.addAudio('/static/mp3/audio_order_new.mp3');
        break
      case 'order_status':
        // 订单状态变更
        const orderStatus = msgContent.orderStatus
        if (orderStatus === OrderStatusEnum.APPLY_CANCEL.value || orderStatus === OrderStatusEnum.CANCELLED.value) {
          audioPlayer.addAudio('/static/mp3/audio_aftersale_cancel.mp3');
        }
        if (orderStatus === OrderStatusEnum.DELIVERY_CANCEL.value) {
          // 配送取消
          audioPlayer.addAudio('/static/mp3/audio_delivery_abnormal.mp3');
        }
        break
      case 'adjust_order':
        // 拣货单调整
        audioPlayer.addAudio('/static/mp3/audio_adjust_order.mp3');
        break
      case 'adjust_refund_order':
        // 拣货单调整
        audioPlayer.addAudio('/static/mp3/audio_adjust_order.mp3');
        break
      case 'after_sale_new':
        // 新售后单
        audioPlayer.addAudio('/static/mp3/audio_aftersale_new.mp3');
        break
    }
    // #endif
    // #ifndef APP-PLUS
    store.commit('SET_SOCKET_ALERT_MESSAGE', msgContent)
    // #endif
  }

  /**
   * 处理接收到的消息
   * @param data
   * @private
   */
  _handleReceivedMessage(data) {
    const { type, content } = data

    switch (type) {
      case MessageType.MESSAGE: // 普通消息
        try {
          const message = JSON.parse(content)
          const { action = '',title , content: msgContent} = message

          // 被强制下线之后，不再继续连接服务端
          if (action === ACTION_999) {
            this.close()
            uni.showModal({
              title: "温馨提示",
              content: "检测到您的账号在其他设备登录，该设备已退出登录！",
              showCancel: false,
              confirmText: '确认',
              success: res => {
                if (res.confirm) {
                  this._handleLogout()
                }
              }
            })
            return
          }

          switch (action) {
            case 'imPrivate': // 私聊消息
              // case 'imGroup': // 群聊消息
              try {
                this._handleIMMessage(action, JSON.parse(msgContent))
              } catch (e) {
                console.warn('log._handleIMMessage', e, msgContent)
              }
              break
            case 'alert':
              this._handleAlertMessage(title,msgContent)
              break
          }
        } catch (e) {
          console.warn('log.MessageType.MESSAGE', e, content)
        }
        break;
      case MessageType.PING: // 收到心跳
        console.log('收到心跳')
        this._sendRawMessage({
          type: SendMessageType.PONG,
          content: PONG_BODY
        }, () => {
          console.log('发送心跳')
        })
        break;
      case MessageType.REPLY_BODY: // 鉴权失败
        try {
          let reply = JSON.parse(content)
          /*
           * 判断是否是握手鉴权失败
           * 终止后续自动重连
           */
          if (reply.key === KEY_HANDSHAKE && reply.code === CODE_UNAUTHORIZED) {
            this.manualStop = true
          }
        } catch (e) {
          console.warn('log.MessageType.REPLY_BODY', e, content)
        }
        break;
      default:
        console.warn('未知消息类型:', data.type);
    }
  }

  /**
   * 处理IM消息
   * @param type
   * @param content
   * @private
   */
  _handleIMMessage(type, content) {
    // vuex中存的消息
    const messageUser = store.getters.messageUser

    // 私聊过滤掉at消息
    if (type === imAction.IM_PRIVATE && content.contentType === imMessageType.AT) {
      return
    }
    // 过滤掉地图消息、自定义消息不展示
    if (content.contentType === imMessageType.MAP || content.contentType === imMessageType.CUSTOM) {
      return
    }
    // 暂时先过滤掉离线消息推送标识
    if (content.title === imOfflinePullType.START || content.title === imOfflinePullType.END) {
      return
    }

    const { tenantId, shops } = this._getStoreInfo()
    const { shopId, senderId, receiverId, thirdChannelId, senderRole, groupId, imMessageId, sendTime } = content
    const tenantMsg =  messageUser[tenantId]
    const shopName = shops.find(item => item.id === `${shopId}`)?.shopName || ''
    // 设置门店名称
    content.shopName = shopName

    try {
      content.content = JSON.parse(Tool.aesDecrypt(content.content))
      content.messageExtra = JSON.parse(content.messageExtra)
    } catch (e) {
      console.warn('log.content.content', e, Tool.aesDecrypt(content.content), content)
    }
    // 过滤掉文本空消息
    if (content.contentType === imMessageType.TEXT && !content.content.text) {
      return
    }

    this._countUnreadMessage(type, tenantId, content)
    const { channelOrderNo, orderId } = content.messageExtra
    const messageGroupKey = `${type}_${shopId}`

    // vuex中存的maxId
    const messageMaxId = store.getters.messageMaxId
    let maxId = imMessageId
    // 公共的会话消息体
    const publicChatBody = {
      shopId: `${shopId}`,
      groupId,
      thirdChannelId,
      shopName,
      // 用户区分群聊，单聊
      type,
      // 用于展示最后一条消息
      lastMessage: content
    }
    // 自行组装好友ID，用于聊天消息的查询
    if (senderRole === imSenderRole.USER || senderRole === imSenderRole.RIDER) {
      publicChatBody.friendId = senderId
    } else if (senderRole === imSenderRole.MERCHANT) {
      publicChatBody.friendId = receiverId
    }
    // 处理关联订单
    if (orderId) {
      publicChatBody.orderId = orderId
      publicChatBody.channelOrderNo = channelOrderNo
    }

    // 存储消息逻辑
    if (!tenantMsg) { // 商户不存在，直接写入
      store.commit('SET_MESSAGE_USER', {
        ...messageUser,
        [tenantId]: {
          [messageGroupKey]: [{ ...publicChatBody, messageList: [content] }]
        }
      })
    } else if (!tenantMsg[messageGroupKey]) { // 消息类型不存在，直接写入
      store.commit('SET_MESSAGE_USER', {
        ...messageUser,
        [tenantId]: {
          ...tenantMsg,
          [messageGroupKey]: [{ ...publicChatBody, messageList: [content] }]
        }
      })
    } else {
      // 存储的门店会话列表
      const shopChatList = tenantMsg[messageGroupKey]
      const shopChatItem = this._chatMessageGroupBy(shopChatList, content)
      if (shopChatItem) {
        // 再判断消息是否存在
        const messageIndex = shopChatItem.messageList.findIndex(item => item.imMessageId === maxId)
        if (messageIndex === -1) {
          shopChatItem.messageList.push(content)
        } else {
          // 已存在的消息不需要更新maxId
          maxId = ''
          shopChatItem.messageList[messageIndex] = content
        }
        // 处理关联订单
        if (orderId) {
          shopChatItem.orderId = orderId
          shopChatItem.channelOrderNo = channelOrderNo
        }
        // 维护lastMessage
        if (sendTime >= shopChatItem.lastMessage.sendTime) {
          shopChatItem.lastMessage = content
        }
      } else {
        shopChatList.push({ ...publicChatBody, messageList: [content] })
      }
      store.commit('SET_MESSAGE_USER', {
        ...messageUser,
        [tenantId]: {
          ...tenantMsg,
          [messageGroupKey]: [...shopChatList]
        }
      })

      this._countUnreadMessage(type, tenantId, content)
    }

    // 更新maxId
    if (maxId) {
      store.commit('SET_MESSAGE_MAX_ID', {
        ...messageMaxId,
        [messageGroupKey]: maxId
      })
    }
  }

  /**
   * 消息分组查找
   * @param shopChatList 当前门店下的会话列表
   * @param content 新消息体
   * @private
   */
  _chatMessageGroupBy(shopChatList, content) {
    const { senderRole, senderId, receiverId } = content
    return shopChatList.find(item => {
      if (item.messageList?.length) {
        const mIndex = item.messageList.findIndex(mItem => {
          // 用户角度分组
          if (senderRole === imSenderRole.USER) {
            return (mItem.senderRole === imSenderRole.USER && mItem.senderId === senderId)
              || (mItem.senderRole === imSenderRole.MERCHANT) && mItem.receiverId === senderId
          }
          // 骑手角度分组
          if (senderRole === imSenderRole.RIDER) {
            return (mItem.senderRole === imSenderRole.RIDER && mItem.senderId === senderId)
              || (mItem.senderRole === imSenderRole.MERCHANT) && mItem.receiverId === senderId
          }
          // 商家角度分组
          if (senderRole === imSenderRole.MERCHANT) {
            return ((mItem.senderRole === imSenderRole.USER || mItem.senderRole === imSenderRole.RIDER) && mItem.senderId === receiverId)
              || (mItem.senderRole === imSenderRole.MERCHANT && mItem.receiverId === receiverId)
          }
          return false
        })
        return mIndex !== -1
      }
      return false
    })
  }

  /**
   * 计算未读消息数量
   * @param type
   * @param tenantId
   * @param content
   * @private
   */
  _countUnreadMessage(type, tenantId, content) {
    const unreadMessageIds = store.getters.unreadMessageIds
    const masterShopUnReadMessageIds = store.getters.masterShopUnReadMessageIds
    const { shopId, status, imMessageId, senderRole } = content
    const messageGroupKey = `${type}_${shopId}`

    if (senderRole === imSenderRole.MERCHANT) {
      return
    }
    const tenantUnReadMessageIds = unreadMessageIds[tenantId]
    const tenantMasterShopUnReadMessageIds = masterShopUnReadMessageIds[tenantId]
    // 将未读消息messageID记录下来
    if (status === imMessageStatus.SUCCESS) {
      // 处理总部场景
      if (!tenantMasterShopUnReadMessageIds) {
        store.commit('SET_MASTER_SHOP_UNREAD_MESSAGE_IDS', {
          [tenantId]: {
            [type]: [imMessageId]
          }
        })
      } else if (!tenantMasterShopUnReadMessageIds[type]) {
        store.commit('SET_MASTER_SHOP_UNREAD_MESSAGE_IDS', {
          ...masterShopUnReadMessageIds,
          [tenantId]: {
            ...tenantMasterShopUnReadMessageIds,
            [type]: [imMessageId]
          }
        })
      } else {
        // 去重
        const messageIdsByIMType = tenantMasterShopUnReadMessageIds[type]
        const duplicateMessageIds = new Set([...messageIdsByIMType, imMessageId])
        store.commit('SET_MASTER_SHOP_UNREAD_MESSAGE_IDS', {
          ...masterShopUnReadMessageIds,
          [tenantId]: {
            ...tenantMasterShopUnReadMessageIds,
            [type]: [...duplicateMessageIds]
          }
        })
      }

      // 处理单门店场景
      if (!tenantUnReadMessageIds) {
        store.commit('SET_UNREAD_MESSAGE_IDS', {
          [tenantId]: { [messageGroupKey]: [imMessageId] }
        })
      } else if (!tenantUnReadMessageIds[messageGroupKey]) {
        store.commit('SET_UNREAD_MESSAGE_IDS', {
          ...unreadMessageIds,
          [tenantId]: {
            ...tenantUnReadMessageIds,
            [messageGroupKey]: [imMessageId]
          }
        })
      } else {
        // push之前需要去重
        const nMessageIds = [...tenantUnReadMessageIds[messageGroupKey]]
        const index = nMessageIds.findIndex(item => item === imMessageId)
        if (index === -1) {
          nMessageIds.push(imMessageId)
        }
        store.commit('SET_UNREAD_MESSAGE_IDS', {
          ...unreadMessageIds,
          [tenantId]: {
            ...tenantUnReadMessageIds,
            [messageGroupKey]: nMessageIds
          }
        })
      }
    } else if (status === imMessageStatus.READ) {
      // 处理总部场景
      const masterIds = [...(tenantMasterShopUnReadMessageIds?.[type] || [])]
      const masterIndex = masterIds.findIndex(item => item === imMessageId)
      if (masterIndex > -1) {
        masterIds.splice(masterIndex, 1)
        store.commit('SET_MASTER_SHOP_UNREAD_MESSAGE_IDS', {
          ...masterShopUnReadMessageIds,
          [tenantId]: {
            ...tenantMasterShopUnReadMessageIds,
            [type]: masterIds
          }
        })
      }

      // 处理单门店场景
      const ids = [...(tenantUnReadMessageIds?.[messageGroupKey] || [])]
      const index = ids.findIndex(item=> item === imMessageId)
      if (index > -1) {
        ids.splice(index, 1)
        store.commit('SET_UNREAD_MESSAGE_IDS', {
          ...unreadMessageIds,
          [tenantId]: {
            ...unreadMessageIds[tenantId],
            [messageGroupKey]: ids
          }
        })
      }
    }
  }

  /**
   * 重连
   * @private
   */
  _scheduleReconnect() {
    console.log('是否主动断开', this.manualStop)
    if (!this.manualStop && this.reconnectCount < this.config.maxReconnect) {
      this.reconnectCount++;
      if (this.reconnectTimer) {
        clearTimeout(this.reconnectTimer)
      }
      this.reconnectTimer = setTimeout(() => {
        console.log(`尝试第 ${this.reconnectCount} 次重连...`);
        this.connect(false);
      }, this.config.reconnectInterval);
    }
  }

  /**
   * 处理错误
   * @param err
   * @private
   */
  _handleError(err) {
    console.error('WebSocket 错误:', err)
    this._scheduleReconnect()
  }

  /**
   * 处理退出登录
   * @private
   */
  _handleLogout() {
    store.dispatch('Logout', true).then(() => {
      navTo('pages/login/index', {}, 'reLaunch')
    })
  }

  /**
   * ios 推送注册
   */
  async _apnsOpen(uuid) {
    
      // if (platform === 'ios'){
        const info = plus.push.getClientInfo();
        const deviceToken = info.token; // 获取deviceToken
        const param = { uuid, deviceToken };
         console.log("deviceToken", param);
        await pushOpen(param);

      // }

  }
}
